import {createEffects, iEffects} from '@peryl/utils/createEffects';
import {$notice, createHttp, iHttpRequestConfig} from "plain-design";
import {createHooks, onBeforeUnmount, reactive} from "@peryl/react-compose";
import {createCounter} from '@peryl/utils/createCounter';
import {http} from '../plain-design/http';

export const createPageQuery = createPageQueryCreator({
  http,
  initialPageIndex: 0,
  initialPageSize: 10,
  method: 'post',
  dataUpdateType: 'append',
  onRequestError: e => {
    $notice.error(e.message || JSON.stringify(e));
  }
});

export function createPageQueryCreator(defaultConfig: iPageQueryDefaultConfig) {
  return <T = Record<string, any>>(useConfig: iPageQueryUseConfig) => {
    const config: iPageQueryConfig = { ...defaultConfig, ...useConfig };
    const hooks = createPageQueryHooks();
    const state: {
      data: T[],
      maxPageIndex: null | number,
      hasNext: boolean,
      currentRequestCount: string | null
      successResponseData: {
        pageIndex: number,
        pageSize: number,
        requestParams: any,
      },
      loading: null | 'reload' | 'load',
    } = reactive({
      /*当前数据*/
      data: [],
      /*已经加载完毕的情况下最大页数*/
      maxPageIndex: null,
      /*是否仍有下一页数据*/
      hasNext: true,
      /*当前的reload计数*/
      currentRequestCount: null as null | string,
      /*load成功之后保存的pageIndex,pageSize以及 requestParams等参数*/
      successResponseData: {
        pageIndex: config.initialPageIndex,
        pageSize: config.initialPageSize,
        requestParams: config.requestParams,
      },
      /*当前请求中的动作类型*/
      loading: null,
    });
    config.effects.push(() => {
      state.data = [];
      state.successResponseData.requestParams = {};
    });
    /**
     * 触发reload的时候，如果有其他loadPage没有执行结束，则其他loadPage执行结束之后不做任何处理，当前reload继续
     * @author  韦胜健
     * @date    2024/10/22 18:49
     */
    const reload = async (data?: { pageSize?: number, requestParams?: any }) => {
      const requestCount = nextRequestCount();
      state.currentRequestCount = requestCount;
      await hooks.onBeforeReload.exec(undefined);
      await load({
        requestCount,
        pageIndex: config.initialPageIndex,
        pageSize: data?.pageSize || config.initialPageSize,
        requestParams: data?.requestParams || state.successResponseData.requestParams,
        loadType: 'reload',
        onAfterRequest: (data) => {
          state.data = data.list;
          state.hasNext = data.hasNext;
          state.maxPageIndex = state.hasNext ? null : config.initialPageIndex;
        }
      });
      await hooks.onAfterReload.exec(undefined);
    };
    const loadNextPage = async () => {
      const pageIndex = state.successResponseData.pageIndex + 1;
      if (state.maxPageIndex != null && pageIndex >= pageIndex) {return;}
      return loadTargetPage(pageIndex);
    };
    const loadPrevPage = () => {
      const pageIndex = state.successResponseData.pageIndex - 1;
      if (pageIndex <= config.initialPageIndex) {return;}
      return loadTargetPage(pageIndex);
    };

    /*加载指定页数据，注意的是，dataUpdateType为append的话是不能这么用的*/
    const loadTargetPage = async (pageIndex: number) => {
      /*正在reload或者其他loadPage时不做处理*/
      if (state.loading) {return;}
      const requestCount = state.currentRequestCount;
      if (requestCount == null) {throw new Error(`Can't load page before reload.`);}
      await load({
        requestCount,
        pageIndex,
        pageSize: state.successResponseData.pageSize,
        requestParams: state.successResponseData.requestParams,
        loadType: 'load',
        onAfterRequest: (data) => {
          if (config.dataUpdateType === 'replace') {
            state.data = data.list;
          } else {
            state.data = [...state.data, ...data.list];
          }
          if (state.hasNext && state.maxPageIndex == null && !data.hasNext) {
            state.hasNext = false;
            state.maxPageIndex = pageIndex;
          }
        }
      });
    };

    const load = async (
      {
        requestCount,
        onAfterRequest,
        pageIndex,
        pageSize,
        requestParams,
        loadType,
      }: {
        requestCount: string,
        pageIndex: number,
        pageSize: number,
        requestParams: any,
        onAfterRequest: (data: { hasNext: boolean, list: T[] }) => void,
        loadType: null | 'reload' | 'load',
      }
    ) => {
      state.loading = loadType;

      try {
        const requestParam = { page: pageIndex, size: pageSize, ...requestParams };
        const requestConfig: iHttpRequestConfig<any> = { url: config.url, method: config.method };
        requestConfig[requestConfig.method === 'get' ? 'params' : 'data'] = requestParam;

        await hooks.onBeforeLoad.exec(undefined);
        const resp = await config.http.request<{ list: T[], hasNext: boolean }>(requestConfig);
        await hooks.onAfterLoad.exec(resp);

        if (state.currentRequestCount !== requestCount) {
          /*当前请求结束时，已经被另一次reload给覆盖了，这里请求结束后不做处理*/
          throw new Error('Request override...');
        }

        onAfterRequest({ hasNext: resp.hasNext, list: resp.list });
        state.successResponseData.pageSize = pageSize;
        state.successResponseData.pageIndex = pageIndex;
        state.successResponseData.requestParams = requestParams;

      } catch (e: any) {
        config.onRequestError(e);
      } finally {
        state.loading = null;
      }
    };

    const isLoading = () => !!pageQuery.state.loading;
    const isEmpty = () => !pageQuery.state.data.length;

    const pageQuery = { state, hooks, config, useConfig, defaultConfig, reload, loadNextPage, loadPrevPage, isLoading, isEmpty };

    return pageQuery;
  };
}

export function createPageQueryHooks() {
  return {
    onAfterReload: createHooks(),
    onBeforeReload: createHooks(),
    onBeforeLoad: createHooks(),
    onAfterLoad: createHooks<(resp: { list: any[], hasNext: boolean }) => void>(),
  };
}

export interface iPageQueryDefaultConfig {
  http: ReturnType<typeof createHttp>;
  initialPageIndex: number;
  initialPageSize: number;
  method: 'get' | 'post';
  dataUpdateType: 'replace' | 'append';
  onRequestError: (e: any) => void,
}

export interface iPageQueryCustomConfig {
  effects: iEffects;
  url: string,
  requestParams?: any,
}

export type iPageQueryUseConfig = Partial<iPageQueryDefaultConfig> & iPageQueryCustomConfig
export type iPageQueryConfig = iPageQueryDefaultConfig & iPageQueryCustomConfig

export type iPageQuery = ReturnType<ReturnType<typeof createPageQueryCreator>>

const nextRequestCount = createCounter('request');

export function useSetupEffects() {
  const { effects: setupEffects } = createEffects();
  onBeforeUnmount(() => setupEffects.clear());
  return { setupEffects };
}
